﻿#pragma once
#include "Logging.h"
#include "getpot.h"
#include "Parser.h"


class GetpotParser : public Parser
{
public:
  void Set(int argc, char* argv[]);
  void Set(std::istream& ss);
  void Set(const std::string& file);

  /// HaveArgv("--mesh-only"): true
  /// HaveArgv("4"): true
  bool HaveArgv(const std::string& option);

  /// HaveVariable("mach"): true
  /// HaveVariable("boundary"): true
  /// HaveVariable("-i"): false
  bool HaveVariable(const std::string& name) const;
  bool HaveSection(const std::string& section_name) const;
  void SetSection(const std::string& prefix);

  template<typename T>
  T Follow(const std::string& option)
  {
    if (!HaveArgv(option))
    {
      _pot.print();
      console::Error(option, "不存在");
    }
    return _pot.follow(T{}, option.c_str());
  }

  template<typename T>
  T Follow(const std::string& option, T&& default)
  {
    return _pot.follow(default, option.c_str());
  }

  template<typename T, typename std::enable_if<!is_vector<T>::value>::type* = nullptr>
  T Get(const std::string& name) const
  {
    if (!HaveVariable(name))
    {
      _pot.print();
      console::Error(name, "不存在");
    }
    return _pot(name, T{});
  }

  template<typename T>
  T Get(std::string&& name, T&& default) const
  {
    return _pot(name, default);
  }

  unsigned VariableSize(const std::string& name) const;

  template<typename T, typename std::enable_if<is_vector<T>::value>::type* = nullptr>
  T Get(const std::string& name, bool required = false) const
  {
    if (!HaveVariable(name) && required)
    {
      _pot.print();
      console::Error(name, "不存在");
    }

    auto size = VariableSize(name);
    T vars;
    if (size == 0)
    {
      return vars;
    }

    vars.resize(size);
    for (unsigned i = 0; i < size; ++i)
      vars[i] = _pot(name, vars[i], i);

    return vars;
  }

  std::string& Usage();

  GetPot& Getpot() { return this->_pot; }

private:
  GetPot _pot;
  std::string _usage;
};


void GetpotParser::Set(int argc, char* argv[])
{
  _pot.parse_command_line(argc, argv);
}


void GetpotParser::Set(std::istream& ss)
{
  _pot.parse_input_stream(ss);
}


void GetpotParser::Set(const std::string& file)
{
  _pot.parse_input_file(file);
}

bool GetpotParser::HaveArgv(const std::string& option)
{
  return _pot.search(option);
}

bool GetpotParser::HaveVariable(const std::string& name) const
{
  return _pot.have_variable(name);
}

bool GetpotParser::HaveSection(const std::string& section_name) const
{
  return _pot.have_section(section_name);
}

unsigned GetpotParser::VariableSize(const std::string& name) const
{
  return _pot.vector_variable_size(name);
}

std::string& GetpotParser::Usage()
{
  return this->_usage;
}

void GetpotParser::SetSection(const std::string& prefix)
{
  if (prefix.empty())
  {
    _pot.set_prefix("");
    return;
  }

  std::string section_name = prefix;

  const char slash('/');
  std::string::const_reverse_iterator it = prefix.rbegin();
  if ((*it) != slash)
    section_name += slash;

  if (!_pot.have_section(section_name))
  {
    console::Error("不存在section: ", section_name);
  }

  _pot.set_prefix(section_name.c_str());
}
